
#ifndef GENERIC_TABLE_CPP

#define GENERIC_TABLE_CPP

#include "generic_table.h"
#include <stdio.h>

//#include "main_container.h"
//#include "errors_warnings.h"
//extern MainContainer * CompilerData;

template <typename DataType> GenericTable<DataType>::GenericTable()
{
#ifdef TRACE
//	CompilerData->LogTrace->ReportEntry("GenericTable()");
#endif

	tableExpandedSize = INIT_TABLE_ENTRIES;
	tableSize = 0;
	table = new DataType * [tableExpandedSize];
	for(int i = 0; i < tableExpandedSize; i++)
	{
		table[i] = 0;
	}

#ifdef TRACE
//	CompilerData->LogTrace->ReportExit("GenericTable()");
#endif
}


template <typename DataType> GenericTable<DataType>::~GenericTable()
{
	if(table != NULL)
	{
		for(int i = 0; i < tableSize; i++)
		{
			if(table[i] != NULL)
			{
				delete table[i];
				table[i] = NULL;
			}
		}
		delete[] table;
		table = NULL;
	}
}




template <typename DataType> bool GenericTable<DataType>::Add(DataType * data)
{
#ifdef TRACE
//	CompilerData->LogTrace->ReportEntry("GenericTable::Add");

//	CompilerData->LogTrace->ReportValue("tableSize", tableSize);
#endif

	bool retVal = this->Insert(data, tableSize);

#ifdef TRACE
//	CompilerData->LogTrace->ReportExit("GenericTable::Add");
#endif
	return retVal;
}


template <typename DataType> bool GenericTable<DataType>::Insert(DataType * data, int index)
{
#ifdef TRACE
//	CompilerData->LogTrace->ReportEntry("GenericTable::Insert");
#endif

	if(index < 0)
	{
#ifdef TRACE
//	CompilerData->LogTrace->ReportExit("GenericTable::Insert");
#endif
		return false;
	}

	if(index >= tableSize)
	{
		index = tableSize;
		// Nikola: ChangeTableToSize(tableSize + 1);
	}
			ChangeTableToSize(tableSize + 1); // Nikola

	for(int i = tableSize - 1; i >= index; --i)
	{
		table[i+1] = table[i];
	}

	table[index] = data;

	tableSize++;

#ifdef TRACE
//	CompilerData->LogTrace->ReportExit("GenericTable::Insert");
#endif
	return true;
}


template <typename DataType> int GenericTable<DataType>::GetCount()
{
	return tableSize;
}


template <typename DataType> DataType * GenericTable<DataType>::GetData(int index)
{
	if(index >= 0 && index < tableSize)
	{
		return table[index];
	}
	else
	{
		return NULL;
	}
}


template <typename DataType> bool GenericTable<DataType>::RemoveAt(int index)
{
#ifdef TRACE
//	CompilerData->LogTrace->ReportEntry("GenericTable::RemoveAt");
#endif

	if(index < 0 || index >= tableSize)
	{
#ifdef TRACE
//	CompilerData->LogTrace->ReportExit("GenericTable::RemoveAt");
#endif
		return false;
	}

	delete table[index];

	for(int i = index; i < tableSize - 1; i++)
	{
		table[i] = table[i+1];
	}

	table[tableSize - 1] = NULL;
	tableSize--;

	ChangeTableToSize(tableSize);
	
#ifdef TRACE
//	CompilerData->LogTrace->ReportExit("GenericTable::RemoveAt");
#endif
	return true;
}



template <typename DataType> bool GenericTable<DataType>::RemoveAtWithoutFreeMem(int index)
{
#ifdef TRACE
//	CompilerData->LogTrace->ReportEntry("GenericTable::RemoveAt");
#endif

	if(index < 0 || index >= tableSize)
	{
#ifdef TRACE
//	CompilerData->LogTrace->ReportExit("GenericTable::RemoveAt");
#endif
		return false;
	}

	for(int i = index; i < tableSize - 1; i++)
	{
		table[i] = table[i+1];
	}

	table[tableSize - 1] = NULL;
	tableSize--;

	ChangeTableToSize(tableSize);
	
#ifdef TRACE
//	CompilerData->LogTrace->ReportExit("GenericTable::RemoveAt");
#endif
	return true;
}


template <typename DataType> void GenericTable<DataType>::ChangeTableToSize(int size)
{
#ifdef TRACE
//	CompilerData->LogTrace->ReportLine("GenericTable:: Performing table resize.");
#endif

	if(size <= INIT_TABLE_ENTRIES)
	{
		return;
	}

	int newTableExpandedSize = -1;
	if(2 * size > tableExpandedSize)
	{
		newTableExpandedSize = 2 * tableExpandedSize;
	}
	else if(size < tableExpandedSize / 4)
	{
		newTableExpandedSize = tableExpandedSize / 2;
	}
	else
	{
		return;
	}

	if(newTableExpandedSize <= INIT_TABLE_ENTRIES)
	{
		return;
	}

	DataType ** newTable = new DataType * [newTableExpandedSize];

	// determine which is the lower limit...
	// higher limit is always the same
	int limit1 = tableExpandedSize < newTableExpandedSize ? tableExpandedSize : newTableExpandedSize;
	int limit2 = newTableExpandedSize;

	for(int i = 0; i < limit1; i++)
	{
		newTable[i] = table[i];
	}

	for(int i = tableExpandedSize; i < limit2; i++)
	{
		newTable[i] = NULL;
	}

	delete[] table;
	table = newTable;

	tableExpandedSize = newTableExpandedSize;
}

#endif
